package com.icloud.cer.rest.msg;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.icloud.cer.rest.util.EncryptUtils;
import com.icloud.cer.rest.util.JsonUtil;


public abstract class AbsMsgObject<T> implements ISerialize, IDeserialize<T> {
	private static final Logger log = LoggerFactory.getLogger(AbsMsgObject.class);
	private transient byte[] data = null;
	private int byteCount;

	protected AbsMsgObject(int byteCount) {
		this.byteCount = byteCount;
	}

	protected AbsMsgObject() {
		this(0);
	}

	@Override
	public T deserialize(byte[] data) throws IOException {
		if (byteCount > 0 && data.length < byteCount) {
			throw new IOException("length of byte " + data.length + " is less then " + byteCount);
		}
		
		byte[] b = new byte[2];
		System.arraycopy(data, 6, b, 0, 2);
		char flag = (char)EncryptUtils.byteArray2int(b);
		log.debug("decode flag:" + flag);
		ByteArrayInputStream bis = new ByteArrayInputStream(data, 0, data.length);
		BDataFilterInputStream dis = new BDataFilterInputStream(bis, flag);
		T obj = doDeserialize(dis);
		bis.close();
		return obj;
	}

	@Override
	public T deserialize(byte[] data, char flag) throws IOException {
		if (byteCount > 0 && data.length < byteCount) {
			throw new IOException("length of byte " + data.length + " is less then " + byteCount);
		}
		BDataFilterInputStream dis = new BDataFilterInputStream(new ByteArrayInputStream(data), flag);
		T obj = doDeserialize(dis);
		dis.close();
		return obj;
	}

	@Override
	public byte[] serialize() throws IOException {
		if (data == null) {
			refreshData();
		}
		return data;
	}

	protected abstract void doSerialize(DataFilterOutputStream dos) throws IOException;

	protected abstract T doDeserialize(BDataFilterInputStream dis) throws IOException;
	    
	private void refreshData() throws IOException {
		ByteArrayOutputStream bos = new ByteArrayOutputStream(byteCount > 0 ? byteCount : 32);
		DataFilterOutputStream dos = new DataFilterOutputStream(bos);
		doSerialize(dos);
		data = bos.toByteArray();
		bos.close();
	}

	@Override
	public String toString() {
		return JsonUtil.serialize(this);
	}

}
